#!/usr/bin/python 
 
import os, sys, subprocess 
from xml.dom import minidom
import urllib2
from ivic.vprocess.MountUtils import *
from ivic.core import Logging

logger = Logging.get_logger('ivic.vprocess.UnionMount')

def bind_mount(src, dst, opt=None): 
    try: 
        command = " ".join(["mount", "-o", opt, "--bind", src, dst]) 
        proc = subprocess.Popen(command, shell=True) 
        proc.wait() 
        if proc.returncode != 0: 
            raise Exception('bind mount [%s-->%s] failed.' % (src, dst)) 
    except Exception, e: 
#        logger.error("%s" % e) 
        raise e
         
def mount_tmpfs(mount_point): 
    try:  
        command = " ".join(["mount -t tmpfs none", mount_point]) 
        proc = subprocess.Popen(command, shell=True) 
        proc.wait() 
    	logger.debug("mount_tmpfs command: %s " % command) 
    except Exception, e:
#    	logger.error("mount_tmpfs error %s: " % e) 
        raise e

def mount_unionfs(branch): 
        command = " ".join(["unionfs-fuse -o default_permissions", branch]) 
        logger.debug(command)
        proc = subprocess.Popen(command, shell=True) 
        proc.wait() 
        if proc.returncode != 0: 
            raise Exception('unionfs-fuse: %s failed.' % branch) 
  
def mount_nfs(url, mount_point):
    try: 
        if not os.path.ismount(mount_point): 
            command = " ".join(["mount -t nfs -o tcp", url, mount_point]) 
            proc = subprocess.Popen(command, shell=True) 
            proc.wait() 
            if proc.returncode != 0: 
                raise Exception('nfs mount: [%s-->%s] failed.' % (url, mount_point))  
    except Exception, e:
        logger.error("%s" %e)

def query_aspire_dfs(query_addr,user):
    try:
        url = "%s/userspace/%s" % (query_addr,user)
        headers = { 'Accept':'application/xml;*/*' }
        req = urllib2.Request(url,None,headers)
        xmldoc = minidom.parseString(urllib2.urlopen(req).read())
        return xmldoc.documentElement.getAttribute("mountname")
    except Exception,e:
        logger.error('query_aspire_dfs: %s' % e)
     
def umount(mount_point): 
    command = " ".join(["umount", mount_point]) 
    os.system(command) 
    proc = subprocess.Popen(command, shell=True) 
    proc.wait() 
    if proc.returncode != 0: 
        raise Exception('unmount %s failed.' % mount_point)  
     
def easy_bind(root_point, branch, option): 
    try: 
        dst = '/'.join([root_point, branch]) 
        if not os.path.exists(dst): os.makedirs(dst, 0777) 
        src = '/' + branch 
        if not os.path.ismount(dst): bind_mount(src, dst, option) 
    except Exception, e: 
        raise e
 
def mount_common(mount_point, ro, rw): 
    if not os.path.exists(mount_point):
        try: 
            os.makedirs(mount_point, 0777)
        except Exception, e:
    	    logger.error("failure to make directory: %s, exception:%s" % (mount_point, e)) 
 
    if os.path.ismount(mount_point): return mount_point 
     
    try: 
        mount_tmpfs(mount_point) 
        for each in ro: easy_bind(mount_point, each, 'ro') 
        for each in rw: easy_bind(mount_point, each, 'rw') 
        return mount_point 
    except Exception, e: 
        raise e 
 
def mount_vsfs(rest, isoeFile, dest, num): 
    try: 
        #./vsfs /tmp/vsfs/gpaint http://localhost/test.isoe  test.isoe 
        #           |                |              |
        #          des              rest          isoeFile
        if not os.path.exists(dest):
            os.system("mkdir -p %s" % dest)
        if os.path.ismount(dest): return
        command = " ".join(['vsfs', dest, rest, isoeFile, num]) 
        proc = subprocess.Popen(command, shell=True) 
        proc.wait() 
        if proc.returncode != 0 : 
            raise Exception('mount_vsfs failure, command is: %s' % command) 
    except Exception, e: 
    	raise e


def umount_vsfs(union_point, vsfs_dest):
    try:
        command = " ".join(["umount", union_point])
        proc = subprocess.Popen(command, shell=True) 
        proc.wait() 
        if proc.returncode != 0 : 
            raise Exception('mount-vsfs failure: %s' % isoeFile) 

        command = " ".join(["umount", vsfs_dest])
        proc = subprocess.Popen(command, shell=True) 
        proc.wait() 
        if proc.returncode != 0 : 
            raise Exception('mount-vsfs failure: %s' % isoeFile) 
    except Exception, e:
    	raise e
 
def prepare_userspace(uconf, user):
    try:
       url = uconf.nfs
       host, space = url.split(':')
       space = "-".join(space.strip('/').split('/')) 
       
       mount_point = "/".join(["/tmp", host, space])
       userspace = '/'.join([mount_point, "home", user])
       rootspace = "/".join([mount_point, "root"])
       
       if not os.path.exists(mount_point):
           try:
               os.makedirs(mount_point, 0777)
           except Exception, e:
               logger.error('[prepare_userspace]:%s' % e)
               raise e
           
#       if not os.path.exists(userspace):
#           os.makedirs(userspace, 0777)
#       if not os.path.exists(rootspace): 
#           os.makedirs(rootspace, 0777)
#           
#       if os.path.ismount(userspace) or os.path.ismount(rootspace):
#           return
       
       if not os.path.ismount(mount_point): 
           mount_nfs(url, mount_point)
           
       try:
           if not os.path.exists(userspace):
               os.makedirs(userspace, 0777)
           if not os.path.exists(rootspace):
               os.makedirs(rootspace, 0777)
       except Exception, e:
           logger.error('[%s]:%s' % (url, e))
       
       umount(mount_point)    
    except Exception, e:
        logger.error('[prepare_userspace]:%s' % e)
    
def mount_userspace(user, uconf, software):
    nfs_url = uconf.nfs
    mount_type = uconf.mount_type
    nfs_point = "/tmp/vsaasdata/%s-%s" % (user,software)
    rootspace = "/".join([nfs_point, "root"])
    userspace = "/".join([nfs_point, "home", user])
    
    if os.path.exists(rootspace) and os.path.exists(userspace) and os.path.ismount(rootspace) and os.path.ismount(userspace):
        return 

    try:
        #prepare_userspace(nfs_url, user)
        if mount_type == "nfs":
            rooturl = '/'.join([nfs_url, "root"])
            userurl = '/'.join([nfs_url, "home", user])
        elif mount_type == "aspire_dfs":
            zone = query_aspire_dfs(uconf.query_addr,user)
            #rooturl = '/'.join([nfs_url,zone,user,".root"])
            #rooturl = "%s%s/%s/.root" % (nfs_url,zone,user)
            rooturl = "%s%s/.root" % (nfs_url,zone)
            #userurl = '/'.join([nfs_url,zone,user])
            #userurl = "%s%s/%s" % (nfs_url,zone,user)
            userurl = "%s%s" % (nfs_url,zone)
        if not os.path.exists(userspace): 
            os.makedirs(userspace, 0777)
        mount_nfs(userurl, userspace)
        
        if not os.path.exists(rootspace): 
            os.makedirs(rootspace, 0777)
        mount_nfs(rooturl, rootspace)

        return nfs_point          
    except Exception, e:
        for each in (rootspace, userspace):
            try:
                umount(each)
                os.removedirs(each)
            except: pass
        logger.error('[nfs]:%s' % e)
        logger.debug("use normal way to join root and home.")  
    return None    
     
        
def vsfs_union(uconf, user, server_dest, software, num,roc = [],rwc = []):
    '''
     example:
     "/tmp/vsaas/gpaint" = "/tmp/vsaas/common" join "/tmp/vsfs/gpaint"
    
     instructions:
     step 0. mount common filesystem directories
     step 1. mount vsfs.isoe to /tmp/vsfs/${software}.isoe
     step 2. unoin the two dirs to /tmp/vsaas/${software}
     
    '''
    usage = "python unionmount.py [software]. software = gpaint|... " 
    
    #do step 0 
    ''' 
    The "ls /" linux command output: 
       bin   cdrom  etc  initrd.img  media  opt   root  selinux  sys  usr  vmlinuz  
       boot  dev    home  lib  lost+found   mnt  proc  sbin  srv  tmp  var 
    ''' 
    
    ro = roc or ['bin', 'etc', 'opt', 'selinux', 'sys', 'usr', 'boot', 'lib', 'sbin', 'srv'] 
    rw = rwc or ['root', 'home', 'mnt', 'proc', 'var', 'tmp','dev'] 
     
    common_point = "/tmp/vsaas/common" 
    
    try: 
        all = [] + ro + rw
        for each in all:
            command = "mkdir -p %s" % "/".join([common_point, each])
            os.system(command)
        mount_common(common_point, ro, rw) 
    except Exception, e: 
    	logger.error("%s" % e) 
          
        
    #step 1. mount vsfs image.
    rest = server_dest + software + ".isoe" 
    vsfs_dest = "/tmp/vsfs/" + user + "/" + software 
    isoeFile = software + ".isoe" 
     
    try: 
        mount_vsfs(rest, isoeFile, vsfs_dest, num) 
    except Exception, e: 
    	logger.error("%s" % e) 
    
    #step 2. union mount
    union_point = "/tmp/vsaas/" + user + "/" + software 
    os.system("mkdir -p %s" % union_point) 
    
    nfs_point = mount_userspace(user,uconf,software)
    if nfs_point:
        branches = [nfs_point+"=rw",common_point + '=rw',vsfs_dest + '=rw'] 
    else:
        branches = [common_point + '=rw',vsfs_dest + '=rw']
#    vsfs_branch = nfs_point+"=rw " + common_point + '=rw' + ':' + vsfs_dest + '=ro ' + union_point 
    vsfs_branch = ":".join(branches) + " " + union_point
    try:
        mount_unionfs(vsfs_branch) 
    except Exception, e: 
    	logger.error("%s" % e)
        
    try:
        devsrc = "/dev"
        devdst = union_point + "/dev"
        bind_mount_i(devsrc,devdst)
    except Exception,e:
        logger.error("%s" % e)
    
if __name__ == "__main__":
    if len(sys.argv) == 4:	
	 server_dest = sys.argv[1]       
	 software = sys.argv[2]
	 num = sys.argv[3]
    else:
	 usage()
    vsfs_union("", server_dest, software, num)
